package cn.wolfcode.wolf2w.resolver;


import cn.wolfcode.wolf2w.annotation.UserParam;
import cn.wolfcode.wolf2w.domain.UserInfo;
import cn.wolfcode.wolf2w.redis.service.IUserInfoRedisService;
import cn.wolfcode.wolf2w.service.IUserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;

/**
 * 能将请求映射方法形式参数中UserInfo对象转换成当前登录用户对象
 * 目的:配置这个后,我们就可以在其他接口(控制器映射方法的参数(userinfo用户对象)前贴@UserParam注解:
 * 我们就可以获取到Redis数据库里面的当前登录用户对象userinfo用户对象了
 * 流程:
 1.spring mvc 会对所有的控制器的请求映射方法中的参数进行解析,
 会分别去匹配所有的参数,包含
 我们自定义的参数解析器,
 每个都会去执行所有的参数的解析方法,
 如果这个方法放回的true,表示可以
 类型一样,能解析,
 然后进入下个方法执行
 就从请求头里面
 获取出当前登录用户对象,然后赋值
 给接口的user用户对象  userinfo.

 2..我们要在api项目的启动类配置用户参数解析器并且将自定义参数解析器加入springmvc中
 我们就可以在其他接口使用user用户对象了.
 */
public class UserInfoArgumentResolver implements HandlerMethodArgumentResolver {
    @Autowired
    private IUserInfoService userInfoService;
    //表示当前的参数解析器,支持哪种参数类型解析
    //此处支持解析UserInfo这种参数类型
    //如果该方法返回true, 表示 UserInfoArgumentResolver 支持对UserInfo类型解析
    public boolean supportsParameter(MethodParameter methodParameter) {
        //判断控制器映射方法的参数类型是UserInfo.class类型的并且贴的注解类型是UserParam类型的,才返回true.
        // 目的是才能接操作resolveArgument方法,给符合要求的参数注入当前登录用户值
        return methodParameter.getParameterType() == UserInfo.class
                &&
                methodParameter.hasParameterAnnotation(UserParam.class)
                ;
    }
    //执行解析逻辑: 请求映射方法形式参数中UserInfo对象转换成当前登录用户对象
    //当上面supportsParameter方法返回true, 才执行这个resolveArgument
    public Object resolveArgument(MethodParameter methodParameter,
                                  ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest,
                                  WebDataBinderFactory webDataBinderFactory) throws Exception {

        // 从用户发送的请求里面的请求头,根据token获取userInof登录登录用户对象出来,返回注入到任意控制器映射方法有
        //贴l@UserParam注解的控制器映射方法的参数(userinfo用户对象.)
        // 就可以直接使用了登录当前用户对象了
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        String token = request.getHeader("token");
        return userInfoService.getUserByToken(token);
    }
}
